package com.atguigu.tingshu.album.service.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.*;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.order.TrackPayVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.util.CollectionUtils;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	VodConstantProperties vodConstantProperties;

	@Autowired
	VodUploadClient vodUploadClient;

	@Autowired
	private TrackInfoMapper trackInfoMapper;

	@Autowired
	VodService vodService;

	@Autowired
	TrackStateService trackStateService;

	@Autowired
	AlbumInfoMapper albumInfoMapper;

	@Autowired
	AlbumStatService albumStatService;

	@Autowired
	UserInfoFeignClient userInfoFeignClient;

	@Autowired
	TrackStatMapper trackStatMapper;

	@Override
	public UploadTrackVo uploadTrack(MultipartFile file) {
		VodUploadRequest request = new VodUploadRequest();
		String uploadTempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
		request.setMediaFilePath(uploadTempPath);
		request.setProcedure(vodConstantProperties.getProcedure());
		VodUploadResponse response = null;
		try {
			response = vodUploadClient.upload(vodConstantProperties.getRegion(), request);
			UploadTrackVo uploadTrackVo = new UploadTrackVo();
			uploadTrackVo.setMediaFileId(response.getFileId());
			uploadTrackVo.setMediaUrl(response.getMediaUrl());
			return uploadTrackVo;
		} catch (Exception e) {
		e.printStackTrace();
		return null ;
	}finally {
		new File(uploadTempPath).delete() ;       // 删除临时文件
	}
	}

	@Transactional
	@Override
	public void saveTrackInfo(TrackInfoVo trackInfoVo) {
		//1 保存声音的基本信息
		TrackInfo trackInfo = new TrackInfo();
		trackInfo.setUserId(AuthContextHolder.getUserId());
		BeanUtils.copyProperties(trackInfoVo, trackInfo);
		trackInfo.setSource(SystemConstant.TRACK_SOURCE_UPLOAD);
		trackInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);

		//根据albumId查询声音列表，获取最大orderNum
		//select * from track_info where album_id = ? order by order_num desc limit 1
		LambdaQueryWrapper<TrackInfo> trackInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
		trackInfoLambdaQueryWrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
		trackInfoLambdaQueryWrapper.orderByDesc(TrackInfo::getOrderNum);
		trackInfoLambdaQueryWrapper.last("limit 1");
		TrackInfo dbTrackInfo = trackInfoMapper.selectOne(trackInfoLambdaQueryWrapper);
		if(dbTrackInfo != null){
			trackInfo.setOrderNum(dbTrackInfo.getOrderNum() + 1);
		}else{
			trackInfo.setOrderNum(1);
		}
		//请求VOD点播接口获取声音时长、大小、类型  以下三个数据用TrackMediaInfoVo封装 定义在单独的实体类
		trackInfo.setMediaDuration(new BigDecimal(vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId()).getDuration()));
		trackInfo.setMediaSize(vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId()).getSize());
		trackInfo.setMediaType(vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId()).getType());
		trackInfo.setMediaUrl(vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId()).getMediaUrl());
		trackInfoMapper.insert(trackInfo);

		//2 初始化声音的统计信息
		ArrayList<TrackStat> trackStatList = new ArrayList<>();
		trackStatList.add(new TrackStat(trackInfo.getId() ,SystemConstant.TRACK_STAT_PLAY,0));
		trackStatList.add(new TrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COLLECT,0));
		trackStatList.add(new TrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_PRAISE,0));
		trackStatList.add(new TrackStat(trackInfo.getId(),SystemConstant.TRACK_STAT_COMMENT,0));
		trackStateService.saveBatch(trackStatList);
		//3 修改专辑基本信息表中声音的数量
		AlbumInfo albumInfo = albumInfoMapper.selectOne(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getId, trackInfo.getAlbumId()));
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
		albumInfoMapper.updateById(albumInfo);
	}

	@Override
	public IPage<TrackListVo> findUserTrackPage(Long pageNo, Long pageSize, TrackInfoQuery trackInfoQuery) {
		Long userId = AuthContextHolder.getUserId();
		trackInfoQuery.setUserId(userId);
		IPage<TrackListVo> page = new Page(pageNo,pageSize);
		return trackInfoMapper.findUserTrackPage(page,trackInfoQuery);
	}

	@Override
	public TrackInfo getTrackInfoById(Long id) {
		return trackInfoMapper.selectById(id);
	}

	/**
	 * 接口为修改声音模块修改，需要考虑将vod中的媒体文件的相关信息同步更新修改
	 * @param trackId
	 * @param trackInfoVo
	 */
	@Override
	public void updateTrackInfoById(Long trackId, TrackInfoVo trackInfoVo) {
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		BeanUtils.copyProperties(trackInfoVo,trackInfo);
		//根据前端提交的数据MediaFileId()与数据库中的MediaFileId()是否一致，如果不一致则需要修改vod中的参数
		if(!trackInfo.getMediaFileId().equals(trackInfoVo.getMediaFileId())){
			TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
			if (trackMediaInfo == null){
				throw new GuiguException(20001,"声音文件不存在");
			}
			trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
			trackInfo.setMediaSize(trackMediaInfo.getSize());
			trackInfo.setMediaType(trackMediaInfo.getType());
			trackInfo.setMediaUrl(trackMediaInfo.getMediaUrl());
		}
		trackInfoMapper.updateById(trackInfo);
	}

	@Transactional
	@Override
	public void removeTrackInfo(Long trackId) {
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Long albumId = trackInfo.getAlbumId();
		//删除声音的基本信息
		trackInfoMapper.deleteById(trackId);
		//删除声音的统计信息
		trackStateService.removeById(trackId);
		//减掉专辑中动物数量信息
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()-1);
		albumInfoMapper.updateById(albumInfo);
		//删除vod中的媒资信息
		vodService.deleteMediaFile(trackInfo.getMediaFileId());
	}

	@Override
	public IPage<AlbumTrackListVo> findAlbumTrackPage(Long albumId, Integer pageNum, Integer pageSize) {
		 IPage<AlbumTrackListVo> page = new Page<>(pageNum,pageSize);
		 trackInfoMapper.findAlbumTrackPage(page,albumId);
		/**
		 * 构建声音付费标记字段的值
		 */
		Long userId = AuthContextHolder.getUserId();
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		//当前专辑下的指定分页声音列表信息
		List<AlbumTrackListVo> albumTrackListVoList = page.getRecords();
		Integer tracksForFree = albumInfo.getTracksForFree(); //获取免费试听的声音集数

		if(userId == null){ //用户未登录
			if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) { //判断该专辑是否为免费的
				//从声音列表中去除声音序号大于试听声音集数的声音
				albumTrackListVoList.stream().filter(albumTrack -> albumTrack.getOrderNum() > tracksForFree).forEach(albumTrack ->albumTrack.setIsShowPaidMark(true));
			}
		}else { //用户已登录
				if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {  //判断指定专辑是否为VIP专辑
					UserInfo userInfo = userInfoFeignClient.findUserInfoById(userId).getData();
					if (userInfo.getIsVip().equals(1)) { //该用户是VIP用户
						if(userInfo.getVipExpireTime().getTime()<System.currentTimeMillis()){ //判断该用户是否VIP过期
							//从声音列表中去除声音序号大于试听声音集数的声音
							albumTrackListVoList.stream().filter(albumTrack -> albumTrack.getOrderNum() > tracksForFree).forEach(albumTrack -> albumTrack.setIsShowPaidMark(true));
						}
					}else { //该用户不是VIP用户
						//从声音列表中去除声音序号大于试听声音集数的声音
						albumTrackListVoList.stream().filter(albumTrack -> albumTrack.getOrderNum() > tracksForFree).forEach(albumTrack ->albumTrack.setIsShowPaidMark(true));
					}
				}else if(SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())){ //判断当前专辑是否为付费专辑，如果为否则无需修改显示字段的默认值
					//筛选出分页声音列表中所有付费的声音并收集其Id号
					List<Long> trackIdList = albumTrackListVoList.stream().filter(albumTrack -> albumTrack.getOrderNum() > tracksForFree).map(AlbumTrackListVo::getTrackId).toList();
					//获取用户三个hi否购买指定专辑下的声音列表
					Map<Long, Long> trackIdsList = userInfoFeignClient.userIsPaidTrack(userId, albumId, trackIdList).getData();
					albumTrackListVoList.stream().filter(albumTrack -> albumTrack.getOrderNum() > tracksForFree).forEach(track->{
						if (trackIdsList.get(track.getTrackId()) == 0) {
							track.setIsShowPaidMark(true);
						}
					});
				}
		}
		page.setRecords(albumTrackListVoList);
		return page;
	}
	@Transactional
	@Override
	public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
		if (trackStatMqVo.getStatType().equals(SystemConstant.TRACK_STAT_PLAY)) {
			LambdaQueryWrapper<TrackStat> queryWrapperTrackStat = new LambdaQueryWrapper<>();
			queryWrapperTrackStat.eq(TrackStat::getTrackId, trackStatMqVo.getTrackId()).eq(TrackStat::getStatType,SystemConstant.TRACK_STAT_PLAY);
			TrackStat trackStat = trackStateService.getOne(queryWrapperTrackStat);
			trackStat.setStatNum(trackStat.getStatNum()+trackStatMqVo.getCount());
			trackStateService.updateById(trackStat);

			LambdaQueryWrapper<AlbumStat> queryWrapperAlbumStat = new LambdaQueryWrapper<>();
			queryWrapperAlbumStat.eq(AlbumStat::getAlbumId,trackStatMqVo.getAlbumId()).eq(AlbumStat::getStatType,SystemConstant.ALBUM_STAT_PLAY);
			AlbumStat albumStat = albumStatService.getOne(queryWrapperAlbumStat);
			albumStat.setStatNum(albumStat.getStatNum() + trackStatMqVo.getCount());
			albumStatService.updateById(albumStat);
		}
	}

	@Override
	public TrackStatVo getTrackStatVo(Long trackId) {
		return trackStatMapper.getTrackStatVo(trackId);
	}

	@Override
	public List<TrackPayVo> findUserTrackPaidList(Long trackId) {

		// 查询用户所点击的声音下面所有的声音列表
		// 1.1 先根据声音的id查询声音信息
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

		// 根据专辑的id查询专辑数据
		Long albumId = trackInfo.getAlbumId();
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);

		// 1.2 根据专辑id和用户所点击的声音的orderNum进行条件查询
		LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
		lambdaQueryWrapper.eq(TrackInfo::getAlbumId , trackInfo.getAlbumId()) ;
		lambdaQueryWrapper.gt(TrackInfo::getOrderNum , trackInfo.getOrderNum()) ;
		List<TrackInfo> trackInfoList = trackInfoMapper.selectList(lambdaQueryWrapper);

		// 查询当前登录用户购买过的声音集合
		Result<List<Long>> userPaidTrackList = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
		List<Long> trackListData = userPaidTrackList.getData();   // 存储的是用户购买过的声音的id

		// 创建一个List集合，存储用户构建声音分集列表的声音id
		List<Long> trackIdNoReaptList = new ArrayList<>() ;
		if(CollectionUtils.isEmpty(trackListData)) {
			trackIdNoReaptList = trackInfoList.stream().map(track -> track.getId()).collect(Collectors.toList());
		}else {		// 存在购买过的声音的id，那么此时就需要从trackInfoList集合中，排除购买过的声音的id，得到未购买过的声音的id集合
			trackIdNoReaptList = trackInfoList.stream().map(track -> track.getId()).filter(stremTrackId -> !trackListData.contains(stremTrackId))
					.collect(Collectors.toList());
		}

		// 创建一个List集合，存储声音的购买分集列表数据
		List<TrackPayVo> trackPayVoList = new ArrayList<>();

		// 构建本集这条数据
		TrackPayVo trackPayVo = new TrackPayVo() ;
		trackPayVo.setName("本集");
		trackPayVo.setPrice(albumInfo.getPrice());
		trackPayVo.setTrackCount(0);
		trackPayVoList.add(trackPayVo) ;

		// 每10集构建一个分集数据
		int size = trackIdNoReaptList.size();
		if(size > 0 && size <= 10) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 10) {		// 构建后10集
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后10集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(10)));
			trackVo.setTrackCount(10);
			trackPayVoList.add(trackVo);
		}

		if(size > 10 && size <= 20) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 20) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后20集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(20)));
			trackVo.setTrackCount(20);
			trackPayVoList.add(trackVo);
		}

		if(size > 20 && size <= 30) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 30) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后30集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(30)));
			trackVo.setTrackCount(30);
			trackPayVoList.add(trackVo);
		}

		if(size > 30 && size <= 40) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 40) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后40集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(40)));
			trackVo.setTrackCount(40);
			trackPayVoList.add(trackVo);
		}

		if(size > 40 && size <= 50) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后" + size + "集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(size)));
			trackVo.setTrackCount(size);
			trackPayVoList.add(trackVo);
		}

		if(size > 50) {
			TrackPayVo trackVo = new TrackPayVo() ;
			trackVo.setName("后50集");
			trackVo.setPrice(albumInfo.getPrice().multiply(new BigDecimal(50)));
			trackVo.setTrackCount(50);
			trackPayVoList.add(trackVo);
		}

		// 返回
		return trackPayVoList;
	}

	@Override
	public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer num) {
		//创建一个List集合存储要购买的声音的数据
		List<TrackInfo> trackInfoList = new ArrayList<>() ;

		// 根据当前的声音的id查询声音信息
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

		// 查询当前登录用户所购买过的声音id集合
		Long albumId = trackInfo.getAlbumId();
		Result<List<Long>> userPaidTrackListResult = userInfoFeignClient.findUserPaidTrackList(albumId);
		List<Long> userPaidTrackIds = userPaidTrackListResult.getData();		// 用户购买过的声音的id的集合

		// 判断num是否是大于0 ， 如果是大于0返回的list集合中就会包含多个声音数据
		if(num > 0) {

			// select * from track_info where album_id = ? and order_num > ? id not in (? , ?)  order by order_num asc limit ?
			LambdaQueryWrapper<TrackInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>() ;
			lambdaQueryWrapper.eq(TrackInfo::getAlbumId , albumId) ;
			lambdaQueryWrapper.gt(TrackInfo::getOrderNum , trackInfo.getOrderNum()) ;
			if(!CollectionUtils.isEmpty(userPaidTrackIds)) {
				lambdaQueryWrapper.notIn( TrackInfo::getId , userPaidTrackIds) ;
			}
			lambdaQueryWrapper.orderByAsc(TrackInfo::getOrderNum) ;
			lambdaQueryWrapper.last("limit " + num) ;
			trackInfoList = trackInfoMapper.selectList(lambdaQueryWrapper);

		}else {
			trackInfoList.add(trackInfo) ;
		}

		return trackInfoList;
	}
}
